package cn.harmonyoslearn.navrouter.datas;

import cn.harmonyoslearn.navrouter.datas.enums.JsonValueType;
import cn.harmonyoslearn.navrouter.datas.interfaces.JsonElementSupplier;
import cn.harmonyoslearn.navrouter.utils.JsonUtil;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonElement;
import com.google.gson.JsonArray;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;

import static java.lang.Integer.*;

public class JsonValue {
    private HashMap<String, JsonValue> jsonMap;
    private JsonElement jsonElement;
    private ArrayList<JsonValue> jsonList;




    public JsonValue(HashMap<String, JsonValue> jsonMap) {
        this.jsonMap = jsonMap;
    }

    public JsonValue(JsonElement jsonElement) {
        this.jsonElement = jsonElement;
    }

    public JsonValue(ArrayList<JsonValue> jsonList) {
        this.jsonList = jsonList;
    }

    public JsonValue() {}

    public JsonValue(String jsonString) {
        jsonMap = getJsonMap(jsonString);
    }




    public JsonValue getChangeValue(String modifyChain) throws Exception {
        ModifyChain modifyChain1 = getModifyChain(modifyChain);

        if (modifyChain1 == null) {
            throw new Exception("modifyChain 内容为空，无法执行，请修改成其他构造函数，或修改 modifyChain 的值");
        }

        JsonValue value = this;
        while (modifyChain1 != null) {
            int index = modifyChain1.index;
            String key = modifyChain1.key;

            if (index == -1) {
                if (!existence(key)) {
                    value.addMap(key, new HashMap<>());
                }
                value = value.value(key);
            } else {
                value = value.arrayList(key).get(index);
            }
            modifyChain1 = modifyChain1.next;
        }

        return value;
    }

    public JsonValue value(String key) {
        if (jsonMap == null) {
            return this;
        }
        JsonValue jsonValue = jsonMap.get(key);
        return Objects.requireNonNullElse(jsonValue, this);
    }

    public JsonValue getValue(String key) {
        return value(key).copy();
    }

    public String getString(String key, String def) {
        String string = getString(key);
        if (string == null) {
            return def;
        }
        return string;
    }

    public String getString(String key) {
        if (jsonMap == null) {
            return null;
        }
        JsonValue jsonValue = jsonMap.get(key);
        String string = jsonValue.toJsonString();
        string = string.replace("\"", "");
        return string;
    }

    public Boolean getBoolean(String key, Boolean def) {
        Boolean aBoolean = getBoolean(key);
        if (aBoolean == null) {
            return def;
        }
        return aBoolean;
    }

    public Boolean getBoolean(String key) {
        if (jsonMap == null) {
            return null;
        }
        String string = getString(key, "");
        return Objects.equals(string, "true");
    }

    public int getInt(String key, int def) {
        if (jsonMap == null) {
            return def;
        }
        String string = getString(key, "");

        try {
            return parseInt(string);
        } catch (Exception e) {
            return def;
        }
    }

    public <T> ArrayList<T> getArrayList(String key, JsonElementSupplier<T> supplier) {
        return arrayList(key, supplier);
    }

    public ArrayList<JsonValue> getArrayList(String key) {
        ArrayList<JsonValue> jsonValues = new ArrayList<>();
        for (JsonValue jsonValue : arrayList(key)) {
            jsonValues.add(jsonValue.copy());
        }
        return jsonValues;
    }

    public <T> ArrayList<T> arrayList(String key, JsonElementSupplier<T> supplier) {
        if (jsonMap == null) {
            return null;
        }
        JsonValue jsonValue = jsonMap.get(key);
        ArrayList<T> jsonValues = new ArrayList<>();

        if (jsonValue.jsonList == null) {
            return null;
        }

        for (JsonValue valueV2 : jsonValue.jsonList) {
            jsonValues.add(supplier.supply(valueV2));
        }
        return jsonValues;
    }

    public ArrayList<JsonValue> arrayList(String key) {
        if (jsonMap == null) {
            return null;
        }

        JsonValue jsonValue = jsonMap.get(key);
        if (jsonValue.jsonList == null) {
            return null;
        }

        return jsonValue.jsonList;
    }




    public void setValue(String value) {
        jsonMap = null;
        jsonList = null;
        jsonElement = new Gson().fromJson("\"" + value + "\"", JsonElement.class);
    }

    public void setValue(Boolean value) {
        jsonMap = null;
        jsonList = null;
        jsonElement = new Gson().fromJson(value.toString(), JsonElement.class);
    }

    public void setValue(int value) {
        jsonMap = null;
        jsonList = null;
        jsonElement = new Gson().fromJson(Integer.toString(value), JsonElement.class);
    }

    public void setValue(HashMap<String, JsonValue> value) {
        jsonMap = value;
        jsonElement = null;
        jsonList = null;
    }

    public void setValue(ArrayList<JsonValue> value) {
        jsonMap = null;
        jsonElement = null;
        jsonList = value;
    }

    /**
     * 按照修改链来修改内容
     *
     * @param modifyChain 修改链，可指定key和index，index是数组的下标；当然不建议使用此方式修改数组内的数据；
     * @param content     修改后的内容
     * @return 修改后的JsonValue，可直接用于转换为Json字符串
     * @throws Exception 调用链格式错误、数组下标错误、等
     */
    public JsonValue setValue(String modifyChain, HashMap<String, JsonValue> content) throws Exception {
        getChangeValue(modifyChain).setValue(content);
        return this;
    }

    /**
     * 按照修改链来修改内容
     *
     * @param modifyChain 修改链，可指定key和index，index是数组的下标；当然不建议使用此方式修改数组内的数据；
     * @param content     修改后的内容
     * @return 修改后的JsonValue，可直接用于转换为Json字符串
     * @throws Exception 调用链格式错误、数组下标错误、等
     */
    public JsonValue setValue(String modifyChain, ArrayList<JsonValue> content) throws Exception {
        getChangeValue(modifyChain).setValue(content);
        return this;
    }

    /**
     * 按照修改链来修改内容
     *
     * @param modifyChain 修改链，可指定key和index，index是数组的下标；当然不建议使用此方式修改数组内的数据；
     * @param content     修改后的内容
     * @return 修改后的JsonValue，可直接用于转换为Json字符串
     * @throws Exception 调用链格式错误、数组下标错误、等
     */
    public JsonValue setValue(String modifyChain, String content) throws Exception {
        getChangeValue(modifyChain).setValue(content);
        return this;
    }

    /**
     * 按照修改链来修改内容
     *
     * @param modifyChain 修改链，可指定key和index，index是数组的下标；当然不建议使用此方式修改数组内的数据；
     * @param content     修改后的内容
     * @return 修改后的JsonValue，可直接用于转换为Json字符串
     * @throws Exception 调用链格式错误、数组下标错误、等
     */
    public JsonValue setValue(String modifyChain, Boolean content) throws Exception {
        getChangeValue(modifyChain).setValue(content);
        return this;
    }

    /**
     * 按照修改链来修改内容
     *
     * @param modifyChain 修改链，可指定key和index，index是数组的下标；当然不建议使用此方式修改数组内的数据；
     * @param content     修改后的内容
     * @return 修改后的JsonValue，可直接用于转换为Json字符串
     * @throws Exception 调用链格式错误、数组下标错误、等
     */
    public JsonValue setValue(String modifyChain, int content) throws Exception {
        getChangeValue(modifyChain).setValue(content);
        return this;
    }




    /**
     * 向当前内容中添加一条字符串，只有类型为 Map 的时候才能插入成功
     */
    public JsonValue addString(String key, String value) {
        if (jsonMap != null) {
            JsonElement jsonElement = new Gson().fromJson("\"" + value + "\"", JsonElement.class);
            jsonMap.put(key, new JsonValue(jsonElement));
        }
        return this;
    }

    /**
     * 向当前 Map中 或 ArrayList 中插入一条数据
     */
    public JsonValue addMap(String key, HashMap<String, JsonValue> map) {
        if (jsonMap != null) {
            jsonMap.put(key, new JsonValue(map));
            return this;
        }
        if (jsonList != null) {
            jsonList.add(new JsonValue(map));
        }
        return this;
    }

    /**
     * 向当前 Map 中插入一条数据
     */
    public JsonValue addArrList(String key, ArrayList<JsonValue> arrayList) {
        if (jsonMap != null) {
            jsonMap.put(key, new JsonValue(arrayList));
        }
        return this;
    }

    public JsonValue addBoolean(String key, boolean value) {
        if (jsonMap != null) {
            jsonMap.put(key, new JsonValue(String.valueOf(value)));
        }

        return this;
    }

    /**
     * 校验 key 是否存在，
     * 如果当前类型不是 Map 则默认不存在
     */
    public Boolean existence(String key) {
        if (jsonMap == null) {
            return false;
        }
        JsonValue value = jsonMap.get(key);
        return value != null;
    }

    /**
     * 获取类型
     */
    public JsonValueType getType() {
        if (this.jsonMap != null) {
            return JsonValueType.MAP;
        }
        if (this.jsonList != null) {
            return JsonValueType.ARRAY_LIST;
        }
        return JsonValueType.FOUNDATION;
    }

    /**
     * 将 JsonValue 数据转化成 Json 字符串
     *
     * @return 转化后的Json字符串
     */
    public String toJsonString() {
        StringBuilder str = new StringBuilder();
        if (jsonMap != null) {
            str.append("{");
            for (String key : jsonMap.keySet()) {
                str.append("\"").append(key).append("\":").append(jsonMap.get(key).toJsonString()).append(",");
            }
            if (jsonMap.size() > 0) {
                str.deleteCharAt(str.length() - 1);
            }
            str.append("}");
        }

        if (jsonElement != null) {
            str = new StringBuilder(jsonElement.toString());
        }

        if (jsonList != null) {
            str = new StringBuilder("[");
            for (JsonValue jsonValue : jsonList) {
                str.append(jsonValue.toJsonString()).append(",");
            }
            if (jsonList.size() > 0) {
                str.deleteCharAt(str.length() - 1);
            }
            str.append("]");
        }

        return str.toString();
    }

    /**
     * 将 JsonValue 深拷贝一份
     *
     * @return 拷贝后的 JsonValue 数据
     */
    public JsonValue copy() {
        JsonValue jsonValue;
        if (jsonMap != null) {
            HashMap<String, JsonValue> jsonValueMap = new HashMap<>();
            for (String key : jsonMap.keySet()) {
                jsonValueMap.put(key, jsonMap.get(key).copy());
            }
            jsonValue = new JsonValue(jsonValueMap);
        } else if (jsonElement != null) {
            jsonValue = new JsonValue(new Gson().fromJson(jsonElement.toString(), JsonElement.class));
        } else {
            ArrayList<JsonValue> jsonValues = new ArrayList<>();
            for (JsonValue jsonValueV2 : jsonList) {
                jsonValues.add(jsonValueV2.copy());
            }
            jsonValue = new JsonValue(jsonValues);
        }
        return jsonValue;
    }

    /**
     * 修正JSON字符串格式
     *
     * @param jsonStr Json字符串
     * @return 修正后的JSON字符串格式
     */
    private String rectify(String jsonStr) {
        // 去除\n
        jsonStr = jsonStr.replace("\n", "");
        jsonStr = jsonStr.replace("\r", "");
        jsonStr = jsonStr.replace(" ", "");

        StringBuilder contentStr = new StringBuilder();
        char lastChar = ' ';
        for (char ch : jsonStr.toCharArray()) {
            if ((ch == '}' || ch == ']') && lastChar == ',') {
                contentStr.delete(contentStr.length() - 1, contentStr.length());
            }
            contentStr.append(ch);
            lastChar = ch;
        }
        return contentStr.toString();
    }

    /**
     * 将 JsonElement 数据转化为 HashMap数据
     * 这个方法只能在 JsonValue(String jsonString) 中使用，因为在此是将Json字符串转化为了Json对象，转化的值必定是一个JsonObject
     *
     * @param jsonElement Json数据，必须是JsonObject
     */
    private HashMap<String, JsonValue> getJsonMap(JsonElement jsonElement) {
        HashMap<String, JsonValue> map = new HashMap<>();
        JsonObject object = (JsonObject) jsonElement;

        for (String key : object.keySet()) {
            JsonElement jsonElement1 = object.get(key);
            if (jsonElement1 != null) {
                map.put(key, jsonElement2JsonValue(jsonElement1));
            }
        }

        return map;
    }

    /**
     * 将 JsonElement 数据转化为 HashMap数据
     * 这个方法只能在 JsonValue(String jsonString) 中使用，因为在此是将Json字符串转化为了Json对象，转化的值必定是一个JsonObject
     *
     * @param jsonString Json数据，必须是标准的 Json格式字符串
     */
    private HashMap<String, JsonValue> getJsonMap(String jsonString) {
        JsonElement jsonElement = JsonUtil.string2JsonObject(jsonString);
        return getJsonMap(jsonElement);
    }

    /**
     * 用于将 jsonElement 数据转化为JsonValue类型的数据
     *
     * @param jsonElement 可以是该类的任何子类
     */
    private JsonValue jsonElement2JsonValue(JsonElement jsonElement) {
        if (jsonElement.getClass().equals(JsonObject.class)) {
            // JsonObject
            HashMap<String, JsonValue> jsonMap1 = getJsonMap(jsonElement);
            return new JsonValue(jsonMap1);
        } else if (jsonElement.getClass().equals(JsonArray.class)) {
            // JsonArray
            ArrayList<JsonValue> jsonValues = new ArrayList<>();
            for (JsonElement element : (JsonArray) jsonElement) {
                JsonValue jsonValue = jsonElement2JsonValue(element);
                jsonValues.add(jsonValue);
            }
            return new JsonValue(jsonValues);
        } else {
            // JsonLiteral
            return new JsonValue(jsonElement);
        }
    }

    /**
     * 格式要求data;names:0;name
     */
    private ModifyChain getModifyChain(String content) throws Exception {
        String[] splits = content.split(";");
        if (splits.length == 0) {
            return null;
        }

        ModifyChain modifyChain = null;
        for (String s : splits) {
            String[] split1 = s.split(":");
            if (split1[0] == null) {
                throw new Exception("ModifyChain 数据格式错误，请检查格式是否为： key:index;key;key");
            }

            String key = split1[0];
            int index = -1;

            try {
                if (split1.length > 1) {
                    index = parseInt(split1[1]);
                }
            } catch (Exception e) {
                throw new Exception("ModifyChain 数据格式错误，请检查格式是否为： key:index;key;key; Error:" + e.getMessage());
            }

            if (modifyChain == null) {
                modifyChain = new ModifyChain(key, index);
            } else {
                modifyChain.next = new ModifyChain(key, index);
            }
        }

        return modifyChain;
    }
}














